We start with the question, what if ggplot had wings? ggplot2 is the de-facto swiss army knife of creating visualizations in R. Laced with the tidyverse, its usefulness has always expanded. Being familiar with the library has put it to use beyond the generation of static, flat images. Here, I seek to set a brief primer of how to extend the powers of ggplot so that it can easily adapt to the interactive screens its graphics are taken to.
Interactivity and graphics
There is a developed and now natural intuition to hover above charts and graphs that we see on the screens we interact with, with an expectation of some response. With the possibilities of sharing ideas born in R through markdown documents, shiny dashboards or HTML formats, the shining armor of ggplot2 loses its sheen in only one-dimension - interactivity, in these mediums. The publication-quality graphics produced through ggplot2 do not necessarily create memorable experiences for users to “interact” with it but instead feel “flat”. While there are several ways to create visualizations specifically for these use cases, there exist several “low-code” means by which plots generated by ggplot can be made interactive and its utility extended.
plotly
Plotly offers a whole suite of graphing libraries across Python, Javascript and R, among others. It helps create interactive, web-based graphics. The plotly R package is a simple, easy to implement way to add interactivity to ggplots. It is based on the JavaScript graphing library plotly.js. In the words of its developers, the package,
“…serializes ggplot2 figures into Plotly’s universal graph JSON. plotly::ggplotly will crawl the ggplot2 figure, extract and translate all of the attributes of the ggplot2 figure into JSON (the colors, the axes, the chart type, etc), and draw the graph with plotly.js.”
Plotly in R can be accessed through its plot_ly and ggplotly arguments. The greatest benefit of ggplotly is that it can be used with ggplot which ensures that the core visualization is one that can be created using familiar ggplot. In this overview, we restrict our scope to only discussing ggplotly.
Features
Plots produced through ggplotly provide opportunities to:
Hover over the chart and view labels associated with the data points.
Zoom, pan and focus on specific areas of the plot.
Download a copy of the plot.
At a glance
Quick view of the possibilities that are discussed on this page.
# Creating a plot of the status of gdp, lifeexp and pop in 2007lifeexpgdpplot <- gapminder %>%filter(year ==2007) %>%ggplot(aes(x = gdpPercap, y = lifeExp,size = pop,color = continent)) +geom_point() +labs(title ="GDP and Lifeexpectancy of countries in 2007") +theme_light() + paletteer::scale_colour_paletteer_d("colRoz::i_lesueurii")# Calling the ggplot objlifeexpgdpplot
Code
# Calling the ggplot obj using ggplotlyggplotly(lifeexpgdpplot)
Code
# Creating a ggplot object with additional attributes for animationlifeexpgdpanim <- gapminder %>%ggplot(aes(x = gdpPercap,y = lifeExp,color = continent)) +geom_point(aes(size = pop,ids = country, frame = year)) +theme_light() + paletteer::scale_colour_paletteer_d("PNWColors::Bay")# Calling the ggplot obj using ggplotlyggplotly(lifeexpgdpanim)
Now that we know about what is possible, let’s get down to work.
Installing plotly
Installing is straightforward. The plotly package can be accessed via CRAN.
install.packages("plotly")
Run ggplotly
We can explore the utility of the package by plotting some charts from the gapminder dataset.
Code
# Loading the required librarieslibrary(gapminder)library(plotly)library(tidyverse)# Creating a plot using the gapminder datasetgapminder %>%filter(year ==2007) %>%ggplot(aes(x = continent, y = lifeExp)) +geom_boxplot(color ="#42047e") +geom_jitter(color ="#f1515e", alpha =0.7) +theme_classic()
Plain ggplot, When we hover around the plot, we can see… that nothing happens!
When we hover around the plot, we can see… that nothing happens!
The primary requirement of using ggploty from the ploty package is to have a ggplot object.(This also means that ggplotly ) In our case we have created lifeexpplot as a ggplot object. We then call this ggplot object using ggplotly.
Code
lifeexpplot <- gapminder %>%filter(year ==2007) %>%ggplot(aes(x = continent, y = lifeExp)) +geom_boxplot(color ="#42047e") +geom_jitter(color ="#f1515e", alpha =0.7) +theme_classic() print(paste0("The lifeexpplot is of the class: ", class(lifeexpplot)))
[1] "The lifeexpplot is of the class: gg"
[2] "The lifeexpplot is of the class: ggplot"
Code
ggplotly(lifeexpplot)
Interactive ggplotly
Caution
Interactivity has entered the screen. Interactivity can get contagious! Tread with caution (or spend hours hovering around scouting for the best labels and tool tips).
Interactivity yields information
We can see that enhancement has made the plot immediately more appealing by being able to provide more information, interactively, on-demand. By being able to show certain information in this interactive manner, we are able to maintain the aesthetics of the original ggplot without overcrowding it with labels and annotations.
The ModeBar
Buttons associated with the Plotly Mode Bar
Aside from the labels, an immediate change that we can see to the plot is that a plotly ribbon, or modebar, is added. Each of these buttons bring additional functionalities to the plot. Handy among these are options to download the plot, and zoom-in and out.
Modifying elements
Without any specific customization, the labels and the ribbon may be overwhelming. It is possible to modify these elements to reflect our use-cases.
config()
It is possible to remove the modebar completely, drop certain buttons or add additional custom buttons using config(). Setting config(displayModeBar = FALSE) removes the modebar entirely. We can pass a list using modeBarButtonsToRemove if there are specific buttons that we want removed from the modebar. The current list of the names of the modebar buttons can be accessed via this link.
tooltip
The default behavior of plotly is to include all the aesthetic mappings from the ggplot layers to the tooltips. In the need of drawing attention to only particular values, the tooltips can be customized to restrict what is shown. A text aesthetic defined in ggplot can be used to create a specific label that can then be accessed via tooltip argument of plotly.
In use-cases where it can help show to changes, over a period of time for instance, adding motion-graphics might be useful. The plot shown above has the added element of a Play button, which can be used to auto-transition between values across the years.
We are able to introduce this interaction using the frame and ids arguments, but primarily through frame. The value that has to be attached to frame would be the one that necessitates the new observation, year in our example. ids represents the object being re-observed and is declared for ensuring smoother transitions between frames.
Tip
There are other ways to produce animated plots in R and produce similar results. gganimate is a package that works on this functionality.
Linked plots
Code
# Limiting the dataset to only values from 2007gapminder_2007 <- gapminder %>%filter(year ==2007)# Creating a shared data framegap_key <-highlight_key(gapminder_2007, ~continent)# Plot 1continent_plot <-ggplot(gap_key, aes(x = lifeExp, fill = continent)) +geom_density(alpha =0.6) + paletteer::scale_fill_paletteer_d("lisa::C_M_Coolidge") +xlab("continents") +theme_classic()# Plot 2country_plot <-ggplot(gap_key, aes(x = gdpPercap,y = lifeExp, size = pop,fill = continent)) +geom_point() +theme_classic() + paletteer::scale_fill_paletteer_d("lisa::C_M_Coolidge")# Plotting them togethersubplot(continent_plot, country_plot) %>%hide_legend() %>%highlight("plotly_hover")
We can use these visualizations when we have linked graphics, where it is helpful to show relevant points on a second plot, based on values selected on another plot. In this example, we are able to isolate the values that belong to countries of a continent, based on the selection of the continent on the first plot.
A shared data frame is created that declares the data frame and the connecting variable that is used between the plots. It is this object that is used to as the data layer for creating the ggplots. When passed through the subplot argument, we are able to create plotly versions with both the plots placed side-by-side.
Tip
There are other ways to create linked plots in R and produce similar results. ggiraph is a package produces similar functionality.
---project: type: website output-dir: docstitle-block-banner: images/gradient.jpegtitle: "Interactive ggplots: a brief introduction"subtitle: "An exercise in plotly-ing"author: name: Cecil Philip John affiliation: Georgetown Universitytoc-title: On this pageformat: html: self-contained: true embed-resources: true toc: true code-fold: true code-tools: trueeditor: visualfig-format: retinafig-align: centertheme: light: flatly dark: darkly---```{r setup, include=FALSE}knitr::opts_chunk$set(warning =FALSE, message =FALSE) library(gapminder)library(plotly)library(tidyverse)```<p><p># Supercharging ggplot2<p>{fig-align="center"}<p>We start with the question, what if ggplot had wings? ggplot2 [](https://cranlogs.r-pkg.org/badges/ggplot2) is the de-facto swiss army knife of creating visualizations in R. Laced with the tidyverse, its usefulness has always expanded. Being familiar with the library has put it to use beyond the generation of static, flat images. Here, I seek to set a brief primer of how to extend the powers of ggplot so that it can easily adapt to the interactive screens its graphics are taken to.<p><p># Interactivity and graphics<p>There is a developed and now natural intuition to hover above charts and graphs that we see on the screens we interact with, with an expectation of some response. With the possibilities of sharing ideas born in R through markdown documents, shiny dashboards or HTML formats, the shining armor of ggplot2 loses its sheen in only one-dimension - interactivity, in these mediums. The publication-quality graphics produced through ggplot2 do not necessarily create memorable experiences for users to "interact" with it but instead feel "flat". While there are several ways to create visualizations specifically for these use cases, there exist several "low-code" means by which plots generated by ggplot can be made interactive and its utility extended.<p><p># plotly<p>Plotly offers a whole suite of [graphing libraries](https://plotly.com/graphing-libraries/ "Plotly graphing libraries") across Python, Javascript and R, among others. It helps create interactive, web-based graphics. The plotly R package [](https://cranlogs.r-pkg.org/badges/plotly) is a simple, easy to implement way to add interactivity to ggplots. It is based on the JavaScript graphing library plotly.js. In the words of its developers, the package,> "...serializes ggplot2 figures into Plotly's [universal graph JSON](http://plot.ly/r/reference/). `plotly::ggplotly` will crawl the ggplot2 figure, extract and translate all of the attributes of the ggplot2 figure into JSON (the colors, the axes, the chart type, etc), and draw the graph with plotly.js.">> \-<https://plotly.com/r/getting-started/>Plotly in R can be accessed through its `plot_ly` and `ggplotly` arguments. The greatest benefit of `ggplotly` is that it can be used with ggplot which ensures that the core visualization is one that can be created using familiar ggplot. In this overview, we restrict our scope to only discussing `ggplotly`.<p><p>## Features<p><p>Plots produced through ggplotly provide opportunities to:- Hover over the chart and view labels associated with the data points.- Zoom, pan and focus on specific areas of the plot.- Download a copy of the plot.<p>## At a glance<p>Quick view of the possibilities that are discussed on this page.::: panel-tabset## ggplot```{r}# Creating a plot of the status of gdp, lifeexp and pop in 2007lifeexpgdpplot <- gapminder %>%filter(year ==2007) %>%ggplot(aes(x = gdpPercap, y = lifeExp,size = pop,color = continent)) +geom_point() +labs(title ="GDP and Lifeexpectancy of countries in 2007") +theme_light() + paletteer::scale_colour_paletteer_d("colRoz::i_lesueurii")# Calling the ggplot objlifeexpgdpplot```## ggplotly```{r}# Calling the ggplot obj using ggplotlyggplotly(lifeexpgdpplot)```## ggplotly - with animation```{r}# Creating a ggplot object with additional attributes for animationlifeexpgdpanim <- gapminder %>%ggplot(aes(x = gdpPercap,y = lifeExp,color = continent)) +geom_point(aes(size = pop,ids = country, frame = year)) +theme_light() + paletteer::scale_colour_paletteer_d("PNWColors::Bay")# Calling the ggplot obj using ggplotlyggplotly(lifeexpgdpanim)```:::<p>Now that we know about what is possible, let's get down to work.<p><p>## Installing plotly<p>Installing is straightforward. The plotly package can be accessed via CRAN.`install.packages("plotly")`<p><p>## Run ggplotly<p>We can explore the utility of the package by plotting some charts from the gapminder dataset.```{r, fig.cap="Plain ggplot, When we hover around the plot, we can see… that nothing happens!", cap-location: margin}# Loading the required librarieslibrary(gapminder)library(plotly)library(tidyverse)# Creating a plot using the gapminder datasetgapminder %>%filter(year ==2007) %>%ggplot(aes(x = continent, y = lifeExp)) +geom_boxplot(color ="#42047e") +geom_jitter(color ="#f1515e", alpha =0.7) +theme_classic() ```<p>*When we hover around the plot, we can see... that nothing happens!*<p><p>The primary requirement of using `ggploty` from the ploty package is to have a ggplot object.(This also means that ggplotly ) In our case we have created `lifeexpplot` as a ggplot object. We then call this ggplot object using ggplotly.<p>```{r}lifeexpplot <- gapminder %>%filter(year ==2007) %>%ggplot(aes(x = continent, y = lifeExp)) +geom_boxplot(color ="#42047e") +geom_jitter(color ="#f1515e", alpha =0.7) +theme_classic() print(paste0("The lifeexpplot is of the class: ", class(lifeexpplot)))```<p>```{r, fig.cap="Interactive ggplotly"}ggplotly(lifeexpplot)```<p>::: callout-cautionInteractivity has entered the screen. Interactivity can get contagious! Tread with caution (or spend hours hovering around scouting for the best labels and tool tips).:::<p>{style="text-align: center;" fig-align="center"}<p>We can see that enhancement has made the plot immediately more appealing by being able to provide more information, interactively, on-demand. By being able to show certain information in this interactive manner, we are able to maintain the aesthetics of the original ggplot without overcrowding it with labels and annotations.<p><p>## The ModeBar<p>{style="text-align: center;" fig-align="center" width="558"}<p>Aside from the labels, an immediate change that we can see to the plot is that a plotly ribbon, or modebar, is added. Each of these buttons bring additional functionalities to the plot. Handy among these are options to download the plot, and zoom-in and out.<p><p>### Modifying elements<p>Without any specific customization, the labels and the ribbon may be overwhelming. It is possible to modify these elements to reflect our use-cases.<p>#### `config()`<p>It is possible to remove the modebar completely, drop certain buttons or add additional custom buttons using `config()`. Setting `config(displayModeBar = FALSE)` removes the modebar entirely. We can pass a list using `modeBarButtonsToRemove` if there are specific buttons that we want removed from the modebar. The current list of the names of the modebar buttons can be accessed via [this link](https://github.com/plotly/plotly.js/blob/master/src/components/modebar/buttons.js "Modebar button names").<p><p>#### `tooltip`<p>The default behavior of plotly is to include all the aesthetic mappings from the ggplot layers to the tooltips. In the need of drawing attention to only particular values, the tooltips can be customized to restrict what is shown. A `text` aesthetic defined in ggplot can be used to create a specific label that can then be accessed via `tooltip` argument of plotly.<p><p>```{r}modplot <- gapminder %>%filter(year ==2007) %>%ggplot(aes(x = continent, y = lifeExp,text = country)) +geom_boxplot(color ="#FFA400FF") +geom_jitter(color ="#088158FF", alpha =0.7) +theme_classic() ggplotly(modplot, tooltip ='text') %>%config(displayModeBar =FALSE)```<p>Here we set the labels as the names of the countries and remove the modebar.## Animation<p>```{r}# Plotting pop_plot <-gapminder %>%filter(country %in% (gapminder %>%filter(year ==2007) %>%slice_max(pop, n =5) %>%pull(country))) %>%ggplot(aes(x = year, y = pop, color = country)) +geom_line(alpha =0.4, linetype ='dashed') +geom_point(aes(size = gdpPercap, ids = country, frame = year))+theme_classic() + paletteer::scale_colour_paletteer_d("fishualize::Antennarius_commerson")ggplotly(pop_plot)```<p>In use-cases where it can help show to changes, over a period of time for instance, adding motion-graphics might be useful. The plot shown above has the added element of a *Play* button, which can be used to auto-transition between values across the years.<p>We are able to introduce this interaction using the `frame` and `ids` arguments, but primarily through `frame`. The value that has to be attached to `frame` would be the one that necessitates the new observation, *year* in our example. `ids` represents the object being re-observed and is declared for ensuring smoother transitions between frames.<p>::: callout-tipThere are other ways to produce animated plots in R and produce similar results. `gganimate`[](https://cran.r-project.org/package=gganimate) is a package that works on this functionality.:::<p><p>## Linked plots<p>```{r}# Limiting the dataset to only values from 2007gapminder_2007 <- gapminder %>%filter(year ==2007)# Creating a shared data framegap_key <-highlight_key(gapminder_2007, ~continent)# Plot 1continent_plot <-ggplot(gap_key, aes(x = lifeExp, fill = continent)) +geom_density(alpha =0.6) + paletteer::scale_fill_paletteer_d("lisa::C_M_Coolidge") +xlab("continents") +theme_classic()# Plot 2country_plot <-ggplot(gap_key, aes(x = gdpPercap,y = lifeExp, size = pop,fill = continent)) +geom_point() +theme_classic() + paletteer::scale_fill_paletteer_d("lisa::C_M_Coolidge")# Plotting them togethersubplot(continent_plot, country_plot) %>%hide_legend() %>%highlight("plotly_hover")```<p>We can use these visualizations when we have linked graphics, where it is helpful to show relevant points on a second plot, based on values selected on another plot. In this example, we are able to isolate the values that belong to countries of a continent, based on the selection of the continent on the first plot.<p>A [shared data frame](https://search.r-project.org/CRAN/refmans/crosstalk/html/SharedData.html "SharedData") is created that declares the data frame and the connecting variable that is used between the plots. It is this object that is used to as the data layer for creating the ggplots. When passed through the `subplot` argument, we are able to create plotly versions with both the plots placed side-by-side.::: callout-tipThere are other ways to create linked plots in R and produce similar results. `ggiraph`[](https://cran.r-project.org/package=gganimate) is a package produces similar functionality.:::<p>## References- <https://plotly-r.com/>